package com.zys.el.time.service.lambda_like;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zys.el.time.constants.RedisConstants;
import com.zys.el.time.entity.ThinkingLike;
import com.zys.el.time.mapper.ThinkingLikeCountMapper;
import com.zys.el.time.mapper.ThinkingLikeMapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

@Service("LambdaThinkingLikeService")
public class LambdaLikeService implements ILambdaLikeService {
    @Resource
    private ThinkingLikeMapper thinkingLikeMapper;
    @Resource
    private ThinkingLikeCountMapper thinkingLikeCountMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 获取查询数量锁
    private final ReentrantLock countDBLock = new ReentrantLock();

    @Override
    public void handleLike(Long thinkingId, Long userId, Boolean status) {
        ThinkingLike thinkingLike = thinkingLikeMapper.getByThinkingIdAndUserId(thinkingId, userId);

        if (thinkingLike != null) { // 记录存在，更新数据库
            thinkingLikeMapper.updateStatusByThinkingIdAndUserId(thinkingId, userId, status ? 1 : 0);
        } else { // 记录不存在，入库
            ThinkingLike tl = new ThinkingLike(thinkingId, userId, status ? 1 : 0);
            thinkingLikeMapper.insert(tl);
        }

        // 更新点赞数量缓存
        String likeKey = RedisConstants.THINK_LIKE_COUNT + thinkingId;
        if (status) {
            stringRedisTemplate.opsForValue().increment(likeKey);
        } else {
            stringRedisTemplate.opsForValue().decrement(likeKey);
        }
        stringRedisTemplate.expire(likeKey, RedisConstants.COMMENT_TTL, TimeUnit.MINUTES);
    }

    @Override
    public Boolean getUserIsLike(Long thinkingId, Long userId) {
        QueryWrapper<ThinkingLike> qw = new QueryWrapper<>();
        qw.lambda().eq(ThinkingLike::getThinkingId, thinkingId).eq(ThinkingLike::getUserId, userId);
        ThinkingLike thinkingLike = thinkingLikeMapper.selectOne(qw);
        return thinkingLike != null && thinkingLike.getStatus() == 1;
    }

    @Override
    public Long getLikeCount(Long thinkingId) {
        String likeKey = RedisConstants.THINK_LIKE_COUNT + thinkingId;
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(likeKey))) { // 缓存存在
            String s = stringRedisTemplate.opsForValue().get(likeKey);
            if (StringUtils.isBlank(s)) return 0L;
            return Long.valueOf(s);
        }

        if (countDBLock.tryLock()) { // 拿到锁
            synchronized (countDBLock) {
                Long likeCount = thinkingLikeCountMapper.getOneByThinkingId(thinkingId);
                stringRedisTemplate.opsForValue().set(likeKey, likeCount != null ? String.valueOf(likeCount) : "0");
                // 唤醒
                countDBLock.notifyAll();
                countDBLock.unlock();
                return likeCount;
            }
        } else {
            try {
                // 阻塞等待
                countDBLock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String s = stringRedisTemplate.opsForValue().get(likeKey);
            if (StringUtils.isBlank(s)) return 0L;
            return Long.valueOf(s);
        }

    }
}
